/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sha256_utils.h"

#include <cstdlib>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <unistd.h>
#include "mbedtls/sha256.h"
#include "loghelper.h"
#include "common_utils.h"

namespace OHOS {
namespace SE {
constexpr unsigned int SHA256_STRING_LEN = 65;
constexpr unsigned int SHA256_LENGTH = 32;
constexpr unsigned int SHA256_TO_STRING_STEP = 2;

std::string Sha256Utils::CalculateHashCode(const std::string &inputStr)
{
    char result[SHA256_STRING_LEN] = {0};
    if (!Sha256Calculate(reinterpret_cast<const unsigned char *>(inputStr.c_str()), inputStr.length(),
        result, SHA256_STRING_LEN)) {
        ErrorLog("CalculateHashCode fail, src = %{public}s", inputStr.c_str());
        return "";
    }
    // Rules read from the chip are all uppercase.
    std::string tmpStr(result);
    std::transform(tmpStr.begin(), tmpStr.end(), tmpStr.begin(), ::toupper);
    InfoLog("CalculateHashCode success, src = %{public}s", tmpStr.c_str());
    return tmpStr;
}

bool Sha256Utils::Sha256Calculate(const unsigned char *input, int len, char *componentId, int componentIdLen)
{
    if (input == nullptr || componentId == nullptr) {
        ErrorLog("Sha256Calculate invalid param");
        return false;
    }
    unsigned char digest[SHA256_LENGTH] = {0};
    mbedtls_sha256_context ctx;
    int ret = memset_s(&ctx, sizeof(ctx), 0, sizeof(ctx));
    if (ret != 0) {
        ErrorLog("init mbedtls_sha256_context failed");
        return false;
    }
    mbedtls_sha256_init(&ctx);
    InfoLog("Sha256Calculate input %{public}s", input);
    int startRet = mbedtls_sha256_starts(&ctx, 0);
    if (startRet != 0) {
        mbedtls_sha256_free(&ctx);
        ErrorLog("mbedtls_sha256_starts_ret failed");
        return false;
    }

    int updateRet = mbedtls_sha256_update(&ctx, input, len);
    if (updateRet != 0) {
        mbedtls_sha256_free(&ctx);
        ErrorLog("mbedtls_sha256_update_ret failed");
        return false;
    }

    int finishRet = mbedtls_sha256_finish(&ctx, digest);
    if (finishRet != 0) {
        mbedtls_sha256_free(&ctx);
        ErrorLog("mbedtls_sha256_finish_ret failed");
        return false;
    }
    mbedtls_sha256_free(&ctx);
    return TransDigestToSha256Result(componentId, componentIdLen, digest);
}

bool Sha256Utils::TransDigestToSha256Result(char *sha256Result, uint32_t componentIdLen, const unsigned char *digest)
{
    for (unsigned int i = 0; i < SHA256_LENGTH; i++) {
        unsigned int deviation = i * SHA256_TO_STRING_STEP;
        if (deviation >= componentIdLen) {
            ErrorLog("deviation len illegal");
            return false;
        }
        int result = sprintf_s(sha256Result + deviation, (componentIdLen - deviation), "%02x", digest[i]);
        if (result <= 0) {
            ErrorLog("generated sha256 failed");
            return false;
        }
    }
    return true;
}
} // namespace SE
} // namespace OHOS